/*
 * Copyright 2009 Jesse McLaughlin (nzjess@gmail.com)
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *         http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.travelfusion.xmlclient.ri.handler.plane;

import static org.travelfusion.xmlclient.util.TfXAPIUtil.closestMidnight;
import static org.travelfusion.xmlclient.util.TfXAPIUtil.formatDate;
import static org.travelfusion.xmlclient.util.TfXAPIUtil.midnight;

import java.util.ArrayList;
import java.util.Date;

import javax.xml.stream.XMLStreamConstants;

import org.travelfusion.xmlclient.handler.HandlesRequestsFor;
import org.travelfusion.xmlclient.impl.handler.AbstractXmlToolRequestStAXResponseHandler;
import org.travelfusion.xmlclient.ri.xobject.plane.XRouterSummary;
import org.travelfusion.xmlclient.ri.xobject.plane.XStartRoutingRequest;
import org.travelfusion.xmlclient.ri.xobject.plane.XStartRoutingResponse;

/**
 * @author Jesse McLaughlin (nzjess@gmail.com)
 */
@HandlesRequestsFor(XStartRoutingRequest.class)
public class StartRoutingHandler extends AbstractXmlToolRequestStAXResponseHandler<XStartRoutingRequest, XStartRoutingResponse> {

  private final RouterSummarySubHandler routerSummaryHandler;

  public StartRoutingHandler() {
    this.routerSummaryHandler = new RouterSummarySubHandler(this);
  }

  @Override
  protected void fillTemplate() throws Exception {
    template.gotoChild();
    template.gotoChild("Origin");
    template.gotoChild("Descriptor").addText(request.getOrigin());
    template.gotoChild("Type").addText(request.getOriginType());
    template.gotoChild("Radius");
    if (request.isOriginAI()) {
      template.delete();
    }
    else {
      template.addText(Integer.toString(request.getOriginRadius()));
      template.gotoChild("UseAirportIntelligence").delete();
    }

    template.gotoParent();
    template.gotoChild("Destination");
    template.gotoChild("Descriptor").addText(request.getDestination());
    template.gotoChild("Type").addText(request.getDestinationType());
    template.gotoChild("Radius");
    if (request.isDestinationAI()) {
      template.delete();
    }
    else {
      template.addText(Integer.toString(request.getDestinationRadius()));
      template.gotoChild("UseAirportIntelligence").delete();
    }

    Date outwardDate = closestMidnight(request.getOutwardDate());
    template.gotoParent().gotoChild("OutwardDates");
    template.gotoChild("DateOfSearch").addText(formatDate(outwardDate));
    template.gotoChild("DepartDateFilter");
    template.gotoChild("DiscardBefore").addText(formatDate(midnight(outwardDate, -request.getOutwardDateDays())));
    template.gotoChild("DiscardAfter").addText(formatDate(midnight(outwardDate, request.getOutwardDateDays() + 1)));
    template.gotoParent();

    template.gotoParent().gotoChild("ReturnDates");
    if (request.getReturnDate() != null) {
      Date returnDate = closestMidnight(request.getReturnDate());
      template.gotoChild("DateOfSearch").addText(formatDate(returnDate));
      template.gotoChild("DepartDateFilter");
      template.gotoChild("DiscardBefore").addText(formatDate(midnight(returnDate, -request.getReturnDateDays())));
      template.gotoChild("DiscardAfter").addText(formatDate(midnight(returnDate, request.getReturnDateDays() + 1)));
      template.gotoParent().gotoParent();
    }
    else {
      template.delete();
    }

    if (!request.isSearchCacheOnly()) {
      template.gotoChild("BookingProfile").delete();
    }

    template.gotoChild("MaxChanges").addText(Integer.toString(request.getMaxChanges()));
    template.gotoChild("MaxHops").addText(Integer.toString(request.getMaxChanges() + 1));

    template.gotoChild("Timeout").addText(Integer.toString(request.getTimeOutSeconds()));

    template.gotoChild("TravellerList");
    addTravellers(request.getNumAdults(), 30);
    addTravellers(request.getNumChildren(), 7);
    addTravellers(request.getNumInfants(), 0);
  }

  private void addTravellers(int count, int age) {
    for (int i = 0; i < count; i++) {
      template.addTag("Traveller").addTag("Age").addText(Integer.toString(age));
      template.gotoParent();
    }
  }

  private static enum State {
    ROOT, //
    ROUTERS
  }

  public XStartRoutingResponse handleResponse() throws Exception {
    XStartRoutingResponse response = new XStartRoutingResponse();
    response.setRouterSummaries(new ArrayList<XRouterSummary>());

    StringBuilder builder = new StringBuilder();
    String currentName = null;
    boolean build = false;

    XRouterSummary routerSummary = null;

    State state = State.ROOT;
    for (int event; ((event = responseReader.next()) != XMLStreamConstants.END_DOCUMENT);) {
      switch (event) {
        case XMLStreamConstants.START_ELEMENT:
          currentName = responseReader.getName().getLocalPart();
          builder.setLength(0);
          switch (state) {
            case ROOT:
              if ("RoutingId".equals(currentName)) {
                build = true;
              }
              else if ("RouterList".equals(currentName)) {
                state = State.ROUTERS;
              }
              break;
            case ROUTERS:
              if ("Router".equals(currentName)) {
                routerSummary = routerSummaryHandler.handleResponse();
                response.getRouterSummaries().add(routerSummary);
              }
              break;
          }
          break;
        case XMLStreamConstants.CHARACTERS:
          if (build) {
            builder.append(responseReader.getTextCharacters(), responseReader.getTextStart(), responseReader.getTextLength());
          }
          break;
        case XMLStreamConstants.END_ELEMENT:
          currentName = responseReader.getName().getLocalPart();
          switch (state) {
            case ROOT:
              if ("RoutingId".equals(currentName)) {
                response.setRoutingId(builder.toString());
                build = false;
              }
              break;
            case ROUTERS:
              if ("RouterList".equals(currentName)) {
                state = State.ROOT;
              }
          }
      }
    }

    return response;
  }
}
